#include <gtest/gtest.h>

#include <memory>
#include <vector>

#include "ezstl_allocator.hpp"

/**
1. 一级配置器 malloc_alloc 的测试用例：
  - 测试了基本的分配和释放功能
  - 测试了内存重分配功能
  - 测试了内存不足处理机制

2. 二级配置器 default_alloc 的测试用例：
  - 测试了小块内存（≤128字节）的分配和释放
  - 测试了大块内存（>128字节）的分配和释放
  - 测试了内存重分配功能

3. 调试分配器 debug_alloc 的测试用例：
  - 测试了基本的分配和释放功能
  - 测试了内存重分配功能
  - 验证了内存统计功能的正确性

4. Allocator 包装器的测试用例：
  - 测试了基本的分配、构造、析构和释放功能
  - 测试了rebind机制
  - 测试了地址获取和最大尺寸查询功能

5. 性能和内存测试：
  - 测试了与std::vector集成使用的情况
  - 测试了大量重复分配释放的场景
  - 测试了混合尺寸内存分配的场景
 */

// 测试一级配置器 malloc_alloc
TEST(MallocAllocTest, AllocateDeallocate) {
  const size_t test_size = 1024;

  // 测试分配
  void* ptr = ezstl::malloc_alloc::allocate(test_size);
  EXPECT_NE(ptr, nullptr);

  // 测试释放
  ezstl::malloc_alloc::deallocate(ptr, test_size);
}

TEST(MallocAllocTest, Reallocate) {
  const size_t old_size = 512;
  const size_t new_size = 1024;

  // 先分配内存
  void* ptr = ezstl::malloc_alloc::allocate(old_size);
  EXPECT_NE(ptr, nullptr);

  // 重新分配
  void* new_ptr = ezstl::malloc_alloc::reallocate(ptr, old_size, new_size);
  EXPECT_NE(new_ptr, nullptr);

  // 释放新内存
  ezstl::malloc_alloc::deallocate(new_ptr, new_size);
}
static void test_handler();
class MallocAllocTest : public ::testing::Test {
 protected:
  friend void test_handler() {
    handler_called = true;
  }
  void SetUp() override {
    handler_called = false;
  }
  void TearDown() override {
    handler_called = false;
  }
  
  static bool handler_called;
};
bool MallocAllocTest::handler_called = false;

// 测试内存不足处理
TEST(MallocAllocTest, OutOfMemoryHandler) {
  // 保存原始处理函数
  void (*old_handler)() = ezstl::malloc_alloc::set_malloc_handler(nullptr);

  // 设置新的处理函数
  ezstl::malloc_alloc::set_malloc_handler((void (*)())test_handler);

  // 这里不实际测试OOM，因为很难模拟
  // 但可以验证处理函数设置是否正常
  EXPECT_NE(ezstl::malloc_alloc::set_malloc_handler(nullptr), nullptr);

  // 恢复原始处理函数
  ezstl::malloc_alloc::set_malloc_handler(old_handler);
}

// 测试二级配置器 default_alloc
TEST(DefaultAllocTest, SmallAllocateDeallocate) {
  const size_t test_size = 64;  // 小于128字节

  // 测试分配
  void* ptr = ezstl::default_alloc::allocate(test_size);
  EXPECT_NE(ptr, nullptr);

  // 测试释放
  ezstl::default_alloc::deallocate(ptr, test_size);
}

TEST(DefaultAllocTest, LargeAllocateDeallocate) {
  const size_t test_size = 256;  // 大于128字节

  // 测试分配
  void* ptr = ezstl::default_alloc::allocate(test_size);
  EXPECT_NE(ptr, nullptr);

  // 测试释放
  ezstl::default_alloc::deallocate(ptr, test_size);
}

TEST(DefaultAllocTest, Reallocate) {
  const size_t small_size = 32;
  const size_t large_size = 256;

  // 测试小块重分配
  void* ptr1 = ezstl::default_alloc::allocate(small_size);
  EXPECT_NE(ptr1, nullptr);

  void* new_ptr1 = ezstl::default_alloc::reallocate(ptr1, small_size, small_size * 2);
  EXPECT_NE(new_ptr1, nullptr);
  ezstl::default_alloc::deallocate(new_ptr1, small_size * 2);

  // 测试大块重分配
  void* ptr2 = ezstl::default_alloc::allocate(large_size);
  EXPECT_NE(ptr2, nullptr);

  void* new_ptr2 = ezstl::default_alloc::reallocate(ptr2, large_size, large_size * 2);
  EXPECT_NE(new_ptr2, nullptr);
  ezstl::default_alloc::deallocate(new_ptr2, large_size * 2);
}

// 测试调试分配器 debug_alloc
TEST(DebugAllocTest, AllocateDeallocate) {
  const size_t test_count = 10;
  const size_t test_size = test_count * sizeof(int);

  // 测试分配
  void* ptr = ezstl::debug_alloc<int>::allocate(test_size);
  EXPECT_NE(ptr, nullptr);

  // 测试释放
  ezstl::debug_alloc<int>::deallocate(ptr, test_size);
}

TEST(DebugAllocTest, Reallocate) {
  const size_t old_count = 5;
  const size_t new_count = 10;
  const size_t old_size = old_count * sizeof(int);
  const size_t new_size = new_count * sizeof(int);

  // 先分配内存
  void* ptr = ezstl::debug_alloc<int>::allocate(old_size);
  EXPECT_NE(ptr, nullptr);

  // 重新分配
  void* new_ptr = ezstl::debug_alloc<int>::reallocate(ptr, old_size, new_size);
  EXPECT_NE(new_ptr, nullptr);

  // 释放新内存
  ezstl::debug_alloc<int>::deallocate(new_ptr, new_size);
}

TEST(DebugAllocTest, Statistics) {
  const size_t test_size1 = 100;
  const size_t test_size2 = 200;

  // 保存初始统计信息
  size_t initial_allocate = ezstl::debug_alloc<int>::allocate_size;
  size_t initial_deallocate = ezstl::debug_alloc<int>::deallocate_size;
  size_t initial_reallocate = ezstl::debug_alloc<int>::reallocate_size;

  // 分配内存
  void* ptr1 = ezstl::debug_alloc<int>::allocate(test_size1);
  EXPECT_NE(ptr1, nullptr);

  void* ptr2 = ezstl::debug_alloc<int>::allocate(test_size2);
  EXPECT_NE(ptr2, nullptr);

  // 释放内存
  ezstl::debug_alloc<int>::deallocate(ptr1, test_size1);
  ezstl::debug_alloc<int>::deallocate(ptr2, test_size2);

  // 验证统计信息
  EXPECT_EQ(ezstl::debug_alloc<int>::allocate_size,
            initial_allocate + test_size1 + test_size2 + 2 * sizeof(size_t*));
  EXPECT_EQ(ezstl::debug_alloc<int>::deallocate_size,
            initial_deallocate + test_size1 + test_size2 + 2 * sizeof(size_t*));
}

// 测试Allocator包装器
TEST(AllocatorTest, AllocateDeallocate) {
  using IntAllocator = ezstl::Allocator<int>;

  const size_t test_count = 10;

  // 测试分配
  int* ptr = IntAllocator::allocate(test_count);
  EXPECT_NE(ptr, nullptr);

  // 测试构造
  for (size_t i = 0; i < test_count; ++i) {
    IntAllocator::construct(ptr + i, static_cast<int>(i));
    EXPECT_EQ(ptr[i], static_cast<int>(i));
  }

  // 测试析构
  for (size_t i = 0; i < test_count; ++i) {
    IntAllocator::destroy(ptr + i);
  }

  // 测试释放
  IntAllocator::deallocate(ptr, test_count);
}
#if 0  // TODO: implement rebind
TEST(AllocatorTest, Rebind) {
    using IntAllocator = Allocator<int>;
    using DoubleAllocator = IntAllocator::rebind<double>::other;
    
    const size_t test_count = 5;
    
    // 使用 rebound allocator 分配double类型内存
    double* ptr = DoubleAllocator::allocate(test_count);
    EXPECT_NE(ptr, nullptr);
    
    // 初始化
    for (size_t i = 0; i < test_count; ++i) {
        DoubleAllocator::construct(ptr + i, static_cast<double>(i) * 1.5);
        EXPECT_DOUBLE_EQ(ptr[i], static_cast<double>(i) * 1.5);
    }
    
    // 清理
    for (size_t i = 0; i < test_count; ++i) {
        DoubleAllocator::destroy(ptr + i);
    }
    
    // 释放
    DoubleAllocator::deallocate(ptr, test_count);
}
#endif

TEST(AllocatorTest, Address) {
  using IntAllocator = ezstl::Allocator<int>;

  int value = 42;
  int* addr = IntAllocator::address(value);
  EXPECT_EQ(addr, &value);
  EXPECT_EQ(*addr, 42);
}

TEST(AllocatorTest, MaxSize) {
  using IntAllocator = ezstl::Allocator<int>;

  size_t max_size = IntAllocator::max_size();
  EXPECT_GT(max_size, 0u);
}

// 内存泄漏和性能测试
TEST(PerformanceTest, VectorWithCustomAllocator) {
  using IntAllocator = ezstl::Allocator<int>;

  // 测试使用自定义allocator的vector
  std::vector<int, IntAllocator> vec;

  const size_t test_count = 1000;
  for (size_t i = 0; i < test_count; ++i) {
    vec.push_back(static_cast<int>(i));
  }

  EXPECT_EQ(vec.size(), test_count);

  for (size_t i = 0; i < test_count; ++i) {
    EXPECT_EQ(vec[i], static_cast<int>(i));
  }
}

TEST(PerformanceTest, MultipleAllocateDeallocate) {
  const size_t iterations = 1000;
  const size_t test_size = 128;

  // 重复分配和释放内存
  for (size_t i = 0; i < iterations; ++i) {
    void* ptr = ezstl::default_alloc::allocate(test_size);
    EXPECT_NE(ptr, nullptr);
    ezstl::default_alloc::deallocate(ptr, test_size);
  }
}

TEST(PerformanceTest, MixedSizeAllocation) {
  const size_t small_size = 32;
  const size_t medium_size = 128;
  const size_t large_size = 1024;

  void* ptr1 = ezstl::default_alloc::allocate(small_size);
  EXPECT_NE(ptr1, nullptr);

  void* ptr2 = ezstl::default_alloc::allocate(medium_size);
  EXPECT_NE(ptr2, nullptr);

  void* ptr3 = ezstl::default_alloc::allocate(large_size);
  EXPECT_NE(ptr3, nullptr);

  ezstl::default_alloc::deallocate(ptr1, small_size);
  ezstl::default_alloc::deallocate(ptr2, medium_size);
  ezstl::default_alloc::deallocate(ptr3, large_size);
}